# Copyright (c) 2017 Adafruit Industries
# Author: Tony DiCola & James DeVito
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import time
import RPi.GPIO
import NBX_OLED
import psutil
import threading




from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

import subprocess

RPi.GPIO.setmode(RPi.GPIO.BCM)
RPi.GPIO.setwarnings(False)
RPi.GPIO.setup(4, RPi.GPIO.OUT)
RPi.GPIO.output(4, True)
# Raspberry Pi pin configuration:
RST = None     # on the PiOLED this pin isnt used
# Note the following are only used with SPI:
DC = 23
SPI_PORT = 0
SPI_DEVICE = 0

# Beaglebone Black pin configuration:
# RST = 'P9_12'
# Note the following are only used with SPI:
# DC = 'P9_15'
# SPI_PORT = 1
# SPI_DEVICE = 0

# 128x32 display with hardware I2C:
disp = NBX_OLED.SSD1306_128_32(rst=RST)

# 128x64 display with hardware I2C:
# disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)

# Note you can change the I2C address by passing an i2c_address parameter like:
# disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST, i2c_address=0x3C)

# Alternatively you can specify an explicit I2C bus number, for example
# with the 128x32 display you would use:
# disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST, i2c_bus=2)

# 128x32 display with hardware SPI:
# disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST, dc=DC, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE, max_speed_hz=8000000))

# 128x64 display with hardware SPI:
# disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST, dc=DC, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE, max_speed_hz=8000000))

# Alternatively you can specify a software SPI implementation by providing
# digital GPIO pin numbers for all the required display pins.  For example
# on a Raspberry Pi with the 128x32 display you might use:
# disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST, dc=DC, sclk=18, din=25, cs=22)

# Initialize library.
disp.begin()

# Clear display.
disp.clear()
disp.display()

# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
width = disp.width
height = disp.height
image = Image.new('1', (width, height))

# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)

# Draw a black filled box to clear the image.
draw.rectangle((0,0,width,height), outline=0, fill=0)

# Draw some shapes.
# First define some constants to allow easy resizing of shapes.
padding = -2
top = padding
bottom = height-padding
# Move left to right keeping track of the current x position for drawing shapes.
x = 0


# Load default font.
font = ImageFont.load_default()

fill_char = ' '
used_char = '|'
char_width = 10
# Alternatively load a TTF font.  Make sure the .ttf font file is in the same directory as the python script!
# Some other nice fonts to try: http://www.dafont.com/bitmap.php
# font = ImageFont.truetype('Minecraftia.ttf', 8)

def get_cpu_load():
    """获取CPU负载"""
    return psutil.cpu_percent(interval=1)

def get_memory_info():
    """获取可用内存与总内存"""
    mem = psutil.virtual_memory()
    return mem.available, mem.total

def get_ip_address():
    """获取IP地址"""
    return psutil.net_if_addrs()['eth0'][0].address

def get_cpu_temperature():
    """获取CPU温度"""
    return psutil.sensors_temperatures()['cpu_thermal'][0].current
cpu_load=0.0
cup_result=""
def get_cpu_load_thread():
    """获取CPU负载的线程"""
    while True:
        global cpu_load,cup_result,used_char,fill_char
        cpu_load = get_cpu_load()
        used = cpu_load/100

        used_width = int(used * char_width)
        if(used_width<char_width):
            used_width+=1
        unused_width = char_width - used_width

        used_str = used_char * used_width
        unused_str = fill_char * unused_width

        cup_result = f"{used_str}{unused_str}"


        # print(f"CPU负载: {cpu_load}%")
        time.sleep(1)

available_memory=0
total_memory=0
mem_result=""
def get_memory_info_thread():
    """获取可用内存与总内存的线程"""
    while True:
        global available_memory, total_memory, mem_result,used_char,fill_char
        available_memory, total_memory = get_memory_info()
        used = (total_memory - available_memory)/total_memory

        used_width = int(used * char_width)
        if(used_width<char_width):
            used_width+=1
        unused_width = char_width - used_width

        used_str = used_char * used_width
        unused_str = fill_char * unused_width

        mem_result = f"{used_str}{unused_str}"


        # print(f"可用内存: {available_memory / 1024 / 1024:.2f} MB")
        # print(f"总内存: {total_memory / 1024 / 1024:.2f} MB")
        time.sleep(5)

ip_address=""
def get_ip_address_thread():
    """获取IP地址的线程"""
    while True:
        global ip_address
        ip_address = get_ip_address()
        # print(f"IP地址: {ip_address}")
        time.sleep(20)

cpu_temperature=0.0
def get_cpu_temperature_thread():
    """获取CPU温度的线程"""
    while True:
        global cpu_temperature
        cpu_temperature = get_cpu_temperature()
        # print(f"CPU温度: {cpu_temperature}")
        time.sleep(3)

def get_network_io_counters():
    """获取网络IO计数器"""
    return psutil.net_io_counters()

bytes_sent=0
bytes_recv=0
def get_network_traffic_thread():
    """获取网络流量"""
    global bytes_sent,bytes_recv
    network_io_counters1 = get_network_io_counters()
    while True:
        time.sleep(1)
        network_io_counters2 = get_network_io_counters()
        bytes_sent = network_io_counters2.bytes_sent - network_io_counters1.bytes_sent
        bytes_recv = network_io_counters2.bytes_recv - network_io_counters1.bytes_recv
        network_io_counters1 = network_io_counters2


def convertBytes():
    sentUnit="B"
    sent=bytes_sent;
    recvUnit="B";
    recv=bytes_recv;
    if(sent > 1024):
        sent=sent/1024
        sentUnit="K"
    if(sent > 1024):
        sent=sent/1024
        sentUnit="M"
    if(recv > 1024):
        recv=recv/1024
        recvUnit="K"
    if(recv > 1024):
        recv=recv/1024
        recvUnit="M"
    sentStr=f"{sent:.3f}"[:5]
    recvStr=f"{recv:.3f}"[:5]
    return sentStr,sentUnit,recvStr,recvUnit



if __name__ == '__main__':
    cpu_load_thread = threading.Thread(target=get_cpu_load_thread)
    memory_info_thread = threading.Thread(target=get_memory_info_thread)
    ip_address_thread = threading.Thread(target=get_ip_address_thread)
    cpu_temperature_thread = threading.Thread(target=get_cpu_temperature_thread)
    net_io_thread = threading.Thread(target=get_network_traffic_thread)

    cpu_load_thread.start()
    memory_info_thread.start()
    ip_address_thread.start()
    cpu_temperature_thread.start()
    net_io_thread.start()

    while True:
        
        sent,sentUnit,recv,recvUnit=convertBytes()
        # Draw a black filled box to clear the image.
        draw.rectangle((0,0,width,height), outline=0, fill=0)

        # Write two lines of text.
        draw.rectangle((0,0,width,height), outline=0, fill=0)
        # 第一行
        draw.text((x, top),       
                  str(f"T:{cpu_temperature:3.0f} {ip_address}"),  
                  font=font, 
                  fill=255) 
        
        # 第二行
        draw.text((x, top+8),     
                  str(f"CPU:[{cup_result}]{cpu_load:4}%"),  
                  font=font, 
                  fill=255)
        # 画成进度条 10个格子
        # 第三行
        draw.text((x, top+16),    
                  str(f"MEM:[{mem_result}]{(available_memory) / 1024 / 1024:4.0f}M"), 
                  font=font, 
                  fill=255)
        
        # 第四行
        draw.text((x, top+25),    
                  str(f"ST:{sent} {sentUnit} RV:{recv} {recvUnit}"),  
                  font=font, 
                  fill=255)
        
        # Display image.
        disp.image(image)
        disp.display()

        # print(f"CPU负载: {cpu_load}%")
        # print(f"可用内存: {available_memory / 1024 / 1024:.2f} MB")
        # print(f"总内存: {total_memory / 1024 / 1024:.2f} MB")
        # print(f"IP地址: {ip_address}")
        # print(f"CPU温度: {cpu_temperature}")
        
        # print(f"发送: {bytes_sent / 1024 / 1024:.2f} MB")
        # print(f"接收: {bytes_recv / 1024 / 1024:.2f} MB")
        time.sleep(1)